[id].tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. import { Head } from "fresh/runtime";
  2. import { HttpError } from "fresh";
  3. import { page, type PageProps } from "fresh";
  4. import { define } from "utils/state.ts";
  5. import { checkToken, getCryptoString } from "utils/server.ts";
  6. import { find } from "utils/db.ts";
  7. import { getCookies } from "@std/http";
  8. import TopBar from "../islands/TopBar.tsx";
  9. import Editor, { EditorMode } from "../islands/Editor.tsx";
  10. import SharePasswordFrame from "../islands/SharePasswordFrame.tsx";
  11. import PageContainer from "../components/layout/PageContainer.tsx";
  12. interface PostProps {
  13. id: string;
  14. title: string;
  15. content: string;
  16. shared: boolean;
  17. isLogined: boolean;
  18. allowMode: EditorMode;
  19. passwordRequired: boolean;
  20. }
  21. export const handler = define.handlers({
  22. async GET(ctx) {
  23. const tokenUserId = checkToken(ctx.req);
  24. const postId = ctx.params.id;
  25. const post = find(
  26. "Post",
  27. tokenUserId
  28. ? { id: postId, user_id: tokenUserId }
  29. : { id: postId, shared: 1 },
  30. ["title", "content", "shared", "share_password"],
  31. );
  32. if (post.length > 0) {
  33. const sharePassword = post[0]["share_password"] as string;
  34. // Non-owner accessing a password-protected shared post
  35. if (!tokenUserId && sharePassword) {
  36. const cookies = getCookies(ctx.req.headers);
  37. const shareCookie = cookies[`pd-share-${postId}`] || "";
  38. const expectedToken = await getCryptoString(
  39. postId + sharePassword,
  40. "MD5",
  41. );
  42. if (shareCookie !== expectedToken) {
  43. return page({
  44. id: postId,
  45. isLogined: false,
  46. allowMode: EditorMode.Read,
  47. title: post[0]["title"] as string,
  48. content: "",
  49. shared: true,
  50. passwordRequired: true,
  51. });
  52. }
  53. }
  54. return page({
  55. id: postId,
  56. isLogined: Boolean(tokenUserId),
  57. allowMode: tokenUserId ? EditorMode.Both : EditorMode.Read,
  58. title: post[0]["title"] as string,
  59. content: post[0]["content"] as string,
  60. shared: post[0]["shared"] === 1,
  61. passwordRequired: false,
  62. });
  63. }
  64. throw new HttpError(404);
  65. },
  66. });
  67. export default function Post(props: PageProps<PostProps>) {
  68. if (props.data.passwordRequired) {
  69. return (
  70. <>
  71. <Head>
  72. <title>{props.data.title}</title>
  73. </Head>
  74. <PageContainer>
  75. <SharePasswordFrame id={props.data.id} title={props.data.title} />
  76. </PageContainer>
  77. </>
  78. );
  79. }
  80. return (
  81. <>
  82. <Head>
  83. <title>{props.data.title}</title>
  84. </Head>
  85. <PageContainer>
  86. <TopBar
  87. id={props.data.id}
  88. title={props.data.title}
  89. shared={props.data.shared}
  90. allowMode={props.data.allowMode}
  91. isLogined={props.data.isLogined}
  92. />
  93. <Editor
  94. id={props.data.id}
  95. content={props.data.content}
  96. allowMode={props.data.allowMode}
  97. />
  98. </PageContainer>
  99. </>
  100. );
  101. }